package com.davidlife.javase.javaio;

import java.io.File;
import java.io.IOException;

/*
 ## 递归
* 递归分类：
    + 直接递归：方法自身调用自己
    + 间接递归：比如A方法调用B方法，B方法调用C方法，C方法调用A方法
* 递归注意事项：
    + 递归一定要有条件限定，明确递归的结束条件，保证递归能够停止下来，否则会发生栈内存溢出
    + 在递归中虽然有限定条件，但是递归次数不能太多，否则也会发生栈内存溢出
    + 构造方法，禁止递归（编译报错。因为构造方法是创建对象使用的，一直递归会导致内存中有无数多个对象，直接编译报错）
* 递归的使用前提：
    + 当调用方法的时候，方法的主体不变，每次调用方法的参数不同，可以使用递归。
 */
public class RecursiveDemo {
    public static void main(String[] args) throws IOException {
        int s = sum(100);
        System.out.println(s);

        int f = factorial(10);
        System.out.println(f);

        createSubs("D:\\tmp2", 5, 5);
        System.out.println("=======================================");
        File file = new File("D:\\tmp2");
        recursiveDirs(file, 0);
    }

    //使用递归计算1 - n之间的和
    public static int sum(int n) {
        if (n == 1) {
            return 1;
        }
        return n + sum(n - 1);
    }
    /*
    使用递归会在线程所分配的栈内存中频发的创建方法，调用方法，销毁方法，（压栈和弹栈），和单纯的
    使用for循环相加计算相比，其效率要底很多。所以肯定不推荐在计算1-n的和时也使用递归。
     */

    //使用递归求n的阶乘
    public static int factorial(int n) {
        if (n == 1) {
            return 1;
        }
        return n * factorial(n - 1);
    }

    //递归打印多级目录
    public static void recursiveDirs(File file, int tabs) {
        for (int i = 0; i < tabs; i++) {
            System.out.print("\t");
        }
        if (file.isDirectory()) {
            System.out.println(file);
            for (File f : file.listFiles()) {
                recursiveDirs(f, tabs + 1);
            }
        } else {
            System.out.println(file);
        }
    }
    /**
     * 随机产生一些目录和文件
     * @param parentDir  在哪个目录下随机产生多级的目录和文件
     * @param depth  目录深度
     * @param breadth  目录广度，即目录下最多有的子目录和子文件之和
     */
    private static void createSubs(String parentDir, int depth, int breadth) throws IOException {
        File p = new File(parentDir);
        if (!p.exists() || p.isFile() || depth==0) {
            return;
        }
        int subNums = (int) (Math.random() * (breadth + 1));
        for (int i = 0; i < subNums; i++) {
            int r = (int) (Math.random() * 2);
            File f;
            if (r == 0) {
                f = new File(parentDir, depth + "-" + (i+1) + ".txt");
                f.createNewFile();
            } else {
                f = new File(parentDir, depth + "-" + (i+1));
                f.mkdir();
            }
            System.out.println("create file: " + f.getAbsolutePath());
            createSubs(f.getAbsolutePath(), depth-1, breadth);
        }

    }
}
